package com.hsc.mvc.bind;

import com.hsc.mvc.MvcFile;
import com.hsc.mvc.ParameterSource;
import com.hsc.mvc.annotations.RequestParam;
import com.hsc.mvc.util.ConversionUtil;

import java.lang.reflect.Parameter;

/**
 * @author
 * @date 2025-05-29
 * @Description 支持使用@RequestParam注解声明的列表参数
 * <p>
 * 普通参数绑定器 ， 1:1   一个参数列表 对应一个 请求参数值
 * * 一个列表参数对应一个参数值
 * * 获取参数值，有可能是文件参数，也可能是非文件参数
 * 参数值可能有两类：  string ， file
 * * 文件参数，起初获得是MvcFile[] 类型的值
 * * 非文件参数，起初获得的是String[]类型的值
 * public void save3(@RequestParam("uname") String[] uname ,@RequestParam("photo") MvcFile[] photo)
 */
public class NormalParameterBinder implements ParameterBindStrategy {
    /**
     * @param parameter       通过反射获取到的参数对象
     * @param parameterSource
     * @return
     */
    @Override
    public Object bind(Parameter parameter, ParameterSource parameterSource) throws Exception {
        // 对应的参数类型 又分为两类: 文件参数{fileParamValue]，非文件参数[paramValues]
        // fileParamValue: 存储的一定是MvcFile[]
        // paramValues: 存储的可能是String，int ,double,long ,float
        // public void save3(@RequestParam("uname") String[] uname ,@RequestParam("photo") MvcFile[] photo)
        // 1、获取注解
        RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
        // 2、获取注解的中的值
        String paramName = requestParam.value();
        // 3、获取参数类型对象 parameter 比如： String[]  MvcFile[]
        Class<?> paramType = parameter.getType();
        // 4、如果是MvcFile
        Object value;
        if (paramType == MvcFile.class || paramType == MvcFile[].class) {
            //对参数进行绑定 如果是文件类型 从参数源中获取文件
            value = parameterSource.getFileParam(paramName);
        } else {
            value = parameterSource.getStringParam(paramName);
        }
        // 4、如果是普通参数
        //  代码至此，就获得了绑定的数据
        //  但此时获得的value属于初始状态 由于我们认为同一个请求名称
        //  会有对应多个请求参数值 所以在框架设计的之处 设计的是数组形式：String[] , MvcFile[]
        //  但是用户在使用的时候只需要并不是直接用数组作为方法参数 ，所以会有以下多种情况
        //  1、用户的参数直接写的是数组 ，这种直接返回即可
        //  2、用户的方法参数是单个参数，@RequestParam("name") String name ，我们需要将数组转换为单个参数
        //  3、用户用的数不同的参数类型，比如基本数据类或者基本类型的包装类 ，我们也需要进行转换 我们拿到的类型是String[]类型的 但是用户需要的是int，所以我们需要转换
        //  MvcFile[] -- MvcFile[] --> MvcFile
        //  String[] -- String[] --> String -- int[] --> int -- double[] --> double
        // value = typeCast(value,parameterType);
        // 对参数进行转换 我们提供一个工具类进行转换  使用策略设计模式拿到具体的策略类进行转换
        // value 我们拿到的原始值
        // paramType 需要转换为用户参数的具体类型
        value = ConversionUtil.convert(value, paramType);
        return value;
    }

    /**
     * 判断当前参数是否支持该参数绑定器
     *
     * @param parameter
     * @return
     */
    @Override
    public boolean isSupport(Parameter parameter) {
        // 获取参数上去的注解 如果不为空则返回true
        // 方法标注有@RequestParam注解
        return parameter.getAnnotation(RequestParam.class) != null;
    }
}
